<?php
/***
 * Candy框架 自动加载类
 * 
 * $Author: 刘森 (fingerboy@qq.com) $
 * $Date: 2019-07-25 02:22:42 $   
 */

declare (strict_types = 1);
namespace Candy\Core;

defined('CANDY') OR die('You Are A Bad Guy. o_O???');

final Class Autoload {
	
	/**
	 *初始化配置
	 */
	public static function loading(){
		if(!defined('ISLOADING')){
			//表示引入状态
			define('ISLOADING', true);
			
			//注册自动加载类
			spl_autoload_register(['Candy\Core\Autoload', 'importClass']);
		}
	}
	
	/**
	 *基类的处理
	 *
	 *@param string 类名
	 */
	public static function importClass(string $className): void
	{
		if(in_array($className, ['memcache', 'memcached'])){
			
		}else{
			//命名空间引导
			$className = str_replace('\\', '/', $className);
			
			//兼容多层APP模式
			$strs = explode('/', $className);
			if(stripos($className, 'APP/Control/') === 0 || stripos($className, 'Extend/Control/') === 0 || stripos($className, 'APP/Addon/') === 0){
				$appName = $strs[2];
				$single = str_replace($strs[0].'/'.$strs[1].'/'.$strs[2].'/', '', $className);
			}else{
				$appName = G('APPNAME');
				$single = str_replace($strs[0].'/'.$strs[1].'/' . (isset($strs[2]) ? $strs[2].'/' : ''), '', $className);
			}
			
			//初始化目录
			$classpath = '';
			
			if(stripos($className, 'Candy/Core/') === 0){
				//基类目录
				$classpath = CANDYROOT. $className .'.class.php';
			}elseif(stripos($className, 'APP/Control/') === 0){
				//控制器目录
				$classpath = RUNTIME.'Controls/'. $appName .'/'. strtolower($single) .'.class.php';
			}elseif(stripos($className, 'Extend/Control/') === 0){
				//控制器目录
				$classpath = RUNTIME.'Controls/'. $appName .'/'. strtolower($single) .'.extend.class.php';
			}elseif(stripos($className, 'APP/Command') === 0){
				//Command命令目录
				[, $command, $app, $path] = explode('/', $className);
				//控制器目录
				$classpath = CANDYROOT.'Application/'. implode('/', array_merge([$app], [$command], explode('/', $path))) .'.class.php';
			}elseif(stripos($className, 'Candy/Extend/') === 0){
				//内置工具类
				$classpath = CANDYPATH.'Class/'. str_replace('Candy/Extend/', '', $className) .'.class.php';
			}elseif(stripos($className, 'APP/Addon/') === 0){
				//插件控制器目录
				$classpath = RUNTIME.'Controls/Addons/'. $appName .'/'. strtolower($single) .'.class.php';
			}elseif($className == 'Candy/APP/Common/Base'){
				//所有项目基类
				$classpath = SOURCEPATH.'Common/Base.class.php';
			}elseif(stripos($className, 'APP/Extend/') === 0){
				//外置工具类
				$classpath = SOURCEPATH.'Class/'. str_replace('APP/Extend/', '', $className) .'.class.php';
			}else{
				$classpath = '';
				//项目内置类库
				if(fileExistsCase(C('APP_PATH') .'Vendor/' . $className . '.php')){
					$classpath = C('APP_PATH') .'Vendor/' . $className . '.php';
				}
				empty($classpath) && $classpath = CANDYPATH.'Vendor/' . $className . '.php';
				if(!fileExistsCase($classpath)){
					//外置扩展类
					$classpath = CANDYROOT . 'Source/Vendor/' . $className . '.php';
					if(!fileExistsCase($classpath)){
						//workerman 内置类库
						$classpath = CANDYPATH.'Vendor/Workerman/' . $className . '.php';
						if(!fileExistsCase($classpath)){
							//特殊路径类库
							$specialClass = G('specialClass');
							$classpath = isset($specialClass[$className]) ? CANDYROOT . 'Source/Vendor/' . $specialClass[$className]['path'] .'/'.$specialClass[$className]['filename'].'.php' : '';
							if(!empty($classpath) && !fileExistsCase($classpath)){
								$classpath = '';
							}
						}
					}
				}
			}

			//引入
			if(!empty($classpath))
			{
				$inres = requireCache($classpath);
				if($inres){
					$type = 5;
					if(stripos($className, 'Candy') === false){
						$single = str_ireplace([$appName, 'action'], '', $single);
						$type = 1;
					}else{
						$single = str_ireplace(['Candy/Core/','Candy/Extend/'], '', $single);
					}
					Debug::addMsg('<b> '. ucfirst($single) .' </b>类', $type);
				}
			}
		}
	}
	
	/**
	 *补全命名空间
	 *
	 *@param string 类名
	 */
	public static function fullClassName(string $className,bool $getPath = false): string
	{
		static $fullName = [];//引入字符串处理类
		
		if(isset($fullName[$className])) return $fullName[$className];
		
		$path = str_replace('\\', '/', $className);
		//列出所有的类
		$classList = [
			[
				'class'=>'\\Candy\\Core\\'. $className, //核心类
				'path'=>CANDYROOT. 'Candy/Core/' . ucfirst(strtolower($className)) .'.class.php'
			],
			[
				'class'=>'\\Candy\\Extend\\'. $className, //内置扩展类
				'path'=>CANDYPATH. 'Class/' . $path .'.class.php'
			],
			[
				'class'=>'\\APP\\Extend\\'. $className, //外置扩展类
				'path'=>SOURCEPATH. 'Class/' . $path .'.class.php'
			],
			[
				'class'=>'\\APP\\Control\\'. C('LAPPNAME') .'\\'. $className .'Action', //当前项目内置类
				'path'=>RUNTIME.'Controls/'. C('RAPPNAME') .'/'. strtolower($className) .'action.class.php'
			],
			[
				'class'=>$className, //内置扩展类
				'path'=>CANDYPATH.'Vendor/' . $path . '.php'
			],
			[
				'class'=>$className, //外置扩展类
				'path'=>CANDYROOT . 'Source/Vendor/' . $path . '.php'
			],
			[
				'class'=>$className, //workerman 内置类库
				'path'=>CANDYPATH.'Vendor/Workerman/' . $path . '.php'
			]
		];
		
		//扩展类库二级目录
		if(in_array($className, ['CacheServer','CacheSession','DBServer','DBService','Storage','AliossStorage','LocalStorage','QiniuStorage','Client','CurlMulti','Http','Smtp','Collect','Mcrypt','Pinyin','Str','Xml','Console','Command','Input','Curd','Output'])){
			switch($className){
				case 'CacheServer':
				case 'CacheSession':
					$classList[] = [
						'class'=>'\\Candy\\Extend\\Cache\\'. $className,
						'path'=>CANDYPATH. 'Class/Cache/' . $className .'.class.php'
					];
					break;
				case 'DBServer':
				case 'DBService':
					$classList[] = [
						'class'=>'\\Candy\\Extend\\DB\\'. $className,
						'path'=>CANDYPATH. 'Class/DB/' . $className .'.class.php'
					];
					break;
				case 'Storage':
				case 'AliossStorage':
				case 'LocalStorage':
				case 'QiniuStorage':
					$classList[] = [
						'class'=>'\\Candy\\Extend\\Storage\\'. $className,
						'path'=>CANDYPATH. 'Class/Storage/' . $className .'.class.php'
					];
					break;
				case 'Client':
				case 'CurlMulti':
				case 'Http':
				case 'Smtp':
					$classList[] = [
						'class'=>'\\Candy\\Extend\\Network\\'. $className,
						'path'=>CANDYPATH. 'Class/Network/' . $className .'.class.php'
					];
					break;
				case 'Collect':
				case 'Mcrypt':
				case 'Pinyin':
				case 'Str':
				case 'Xml':
					$classList[] = [
						'class'=>'\\Candy\\Extend\\Str\\'. $className,
						'path'=>CANDYPATH. 'Class/Str/' . $className .'.class.php'
					];
					break;
				case 'Console':
				case 'Command':
				case 'Input':
				case 'Curd':
				case 'Output':
					$classList[] = [
						'class'=>'\\Candy\\Extend\\Console\\'. $className,
						'path'=>CANDYPATH. 'Class/Console/' . $className .'.class.php'
					];
					break;
			}
		}
		$total = count($classList);
		$i = 0;
		do{
			if(fileExistsCase($classList[$i]['path'])){
				requireCache($classList[$i]['path']);
				$fullName[$className] = $classList[$i]['class'];
				return $getPath ? $classList[$i]['path'] : $classList[$i]['class'];
			}
			$i++;
		}while($i < $total);
		
		return $getPath ? '' : $className; 
	}
}
